home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_300 / 334_01 / graphics.c < prev    next >
Text File  |  1991-02-04  |  37KB  |  1,309 lines

  1. /* GNUPLOT - graphics.c */
  2. /*
  3.  * Copyright (C) 1986, 1987, 1990   Thomas Williams, Colin Kelley
  4.  *
  5.  * Permission to use, copy, and distribute this software and its
  6.  * documentation for any purpose with or without fee is hereby granted, 
  7.  * provided that the above copyright notice appear in all copies and 
  8.  * that both that copyright notice and this permission notice appear 
  9.  * in supporting documentation.
  10.  *
  11.  * Permission to modify the software is granted, but not the right to
  12.  * distribute the modified code.  Modifications are to be distributed 
  13.  * as patches to released version.
  14.  *  
  15.  * This software  is provided "as is" without express or implied warranty.
  16.  * 
  17.  *
  18.  * AUTHORS
  19.  * 
  20.  *   Original Software:
  21.  *     Thomas Williams,  Colin Kelley.
  22.  * 
  23.  *   Gnuplot 2.0 additions:
  24.  *       Russell Lang, Dave Kotz, John Campbell.
  25.  * 
  26.  * send your comments or suggestions to (pixar!info-gnuplot@sun.com).
  27.  * 
  28.  */
  29.  
  30. #include <stdio.h>
  31. #include <math.h>
  32. #include <assert.h>
  33. #include "plot.h"
  34. #include "setshow.h"
  35.  
  36. extern char *strcpy(),*strncpy(),*strcat();
  37.  
  38. void plot_impulses();
  39. void plot_lines();
  40. void plot_points();
  41. void plot_dots();
  42. void edge_intersect();
  43. BOOLEAN two_edge_intersect();
  44.  
  45. #ifndef max        /* Lattice C has max() in math.h, but shouldn't! */
  46. #define max(a,b) ((a > b) ? a : b)
  47. #endif
  48.  
  49. #ifndef min
  50. #define min(a,b) ((a < b) ? a : b)
  51. #endif
  52.  
  53. #define inrange(z,min,max) ((min<max) ? ((z>=min)&&(z<=max)) : ((z>=max)&&(z<=min)) )
  54.  
  55. /* Define the boundary of the plot
  56.  * These are computed at each call to do_plot, and are constant over
  57.  * the period of one do_plot. They actually only change when the term
  58.  * type changes and when the 'set size' factors change. 
  59.  */
  60. static int xleft, xright, ybot, ytop;
  61.  
  62. /* Boundary and scale factors, in user coordinates */
  63. /* x_min, x_max, y_min, y_max are local to this file and
  64.  * are not the same as variables of the same names in other files
  65.  */
  66. static double x_min, x_max, y_min, y_max;
  67. static double xscale, yscale;
  68.  
  69. /* And the functions to map from user to terminal coordinates */
  70. #define map_x(x) (int)(xleft+(x-x_min)*xscale+0.5) /* maps floating point x to screen */ 
  71. #define map_y(y) (int)(ybot+(y-y_min)*yscale+0.5)    /* same for y */
  72.  
  73. /* (DFK) Watch for cancellation error near zero on axes labels */
  74. #define SIGNIF (0.01)        /* less than one hundredth of a tic mark */
  75. #define CheckZero(x,tic) (fabs(x) < ((tic) * SIGNIF) ? 0.0 : (x))
  76. #define NearlyEqual(x,y,tic) (fabs((x)-(y)) < ((tic) * SIGNIF))
  77.  
  78. /* (DFK) For some reason, the Sun386i compiler screws up with the CheckLog 
  79.  * macro, so I write it as a function on that machine.
  80.  */
  81. #ifndef sun386
  82. /* (DFK) Use 10^x if logscale is in effect, else x */
  83. #define CheckLog(log, x) ((log) ? pow(10., (x)) : (x))
  84. #else
  85. static double
  86. CheckLog(log, x)
  87.      BOOLEAN log;
  88.      double x;
  89. {
  90.   if (log)
  91.     return(pow(10., x));
  92.   else
  93.     return(x);
  94. }
  95. #endif /* sun386 */
  96.  
  97. double
  98. LogScale(coord, islog, what, axis)
  99.     double coord;            /* the value */
  100.     BOOLEAN islog;            /* is this axis in logscale? */
  101.     char *what;            /* what is the coord for? */
  102.     char *axis;            /* which axis is this for ("x" or "y")? */
  103. {
  104.     if (islog) {
  105.        if (coord <= 0.0) {
  106.           char errbuf[100];        /* place to write error message */
  107.         (void) sprintf(errbuf,"%s has %s coord of %g; must be above 0 for log scale!",
  108.                 what, axis, coord);
  109.           (*term_tbl[term].text)();
  110.           (void) fflush(outfile);
  111.           int_error(errbuf, NO_CARET);
  112.        } else
  113.         return(log10(coord));
  114.     }
  115.     return(coord);
  116. }
  117.  
  118. /* borders of plotting area */
  119. /* computed once on every call to do_plot */
  120. boundary(scaling)
  121.     BOOLEAN scaling;        /* TRUE if terminal is doing the scaling */
  122. {
  123.     register struct termentry *t = &term_tbl[term];
  124.     xleft = (t->h_char)*12;
  125.     xright = (scaling ? 1 : xsize) * (t->xmax) - (t->h_char)*2 - (t->h_tic);
  126.     ybot = (t->v_char)*5/2 + 1;
  127.     ytop = (scaling ? 1 : ysize) * (t->ymax) - (t->v_char)*3/2 - 1;
  128. }
  129.  
  130.  
  131. double dbl_raise(x,y)
  132. double x;
  133. int y;
  134. {
  135. register int i;
  136. double val;
  137.  
  138.     val = 1.0;
  139.     for (i=0; i < abs(y); i++)
  140.         val *= x;
  141.     if (y < 0 ) return (1.0/val);
  142.     return(val);
  143. }
  144.  
  145.  
  146. double make_tics(tmin,tmax,logscale)
  147. double tmin,tmax;
  148. BOOLEAN logscale;
  149. {
  150. register double xr,xnorm,tics,tic,l10;
  151.  
  152.     xr = fabs(tmin-tmax);
  153.     
  154.     l10 = log10(xr);
  155.     if (logscale) {
  156.         tic = dbl_raise(10.0,(l10 >= 0.0 ) ? (int)l10 : ((int)l10-1));
  157.         if (tic < 1.0)
  158.             tic = 1.0;
  159.     } else {
  160.         xnorm = pow(10.0,l10-(double)((l10 >= 0.0 ) ? (int)l10 : ((int)l10-1)));
  161.         if (xnorm <= 2)
  162.             tics = 0.2;
  163.         else if (xnorm <= 5)
  164.             tics = 0.5;
  165.         else tics = 1.0;    
  166.         tic = tics * dbl_raise(10.0,(l10 >= 0.0 ) ? (int)l10 : ((int)l10-1));
  167.     }
  168.     return(tic);
  169. }
  170.  
  171.  
  172. do_plot(plots, pcount, min_x, max_x, min_y, max_y)
  173. struct curve_points *plots;
  174. int pcount;            /* count of plots in linked list */
  175. double min_x, max_x;
  176. double min_y, max_y;
  177. {
  178. register struct termentry *t = &term_tbl[term];
  179. register int curve, xaxis_y, yaxis_x;
  180. register struct curve_points *this_plot;
  181. register double ytic, xtic;
  182. register int xl, yl;
  183.             /* only a Pyramid would have this many registers! */
  184. double xtemp, ytemp;
  185. struct text_label *this_label;
  186. struct arrow_def *this_arrow;
  187. BOOLEAN scaling;
  188.  
  189. /* store these in variables global to this file */
  190. /* otherwise, we have to pass them around a lot */
  191.      x_min = min_x;
  192.      x_max = max_x; 
  193.      y_min = min_y;
  194.      y_max = max_y;
  195.  
  196.     if (polar) {
  197.         /* will possibly change x_min, x_max, y_min, y_max */
  198.         polar_xform(plots,pcount);
  199.     }
  200.  
  201.     if (y_min == VERYLARGE || y_max == -VERYLARGE)
  202.         int_error("all points undefined!", NO_CARET);
  203.  
  204.     if (x_min == VERYLARGE || x_max == -VERYLARGE)
  205.         int_error("all points undefined!", NO_CARET);
  206.  
  207. /*    Apply the desired viewport offsets. */
  208.      if (y_min < y_max) {
  209.         y_min -= boff;
  210.         y_max += toff;
  211.     } else {
  212.         y_max -= boff;
  213.         y_min += toff;
  214.     }
  215.      if (x_min < x_max) {
  216.         x_min -= loff;
  217.         x_max += roff;
  218.     } else {
  219.         x_max -= loff;
  220.         x_min += roff;
  221.     }
  222.  
  223. /* SETUP RANGES, SCALES AND TIC PLACES */
  224.     if (ytics && yticdef.type == TIC_COMPUTED) {
  225.        ytic = make_tics(y_min,y_max,log_y);
  226.     
  227.        if (autoscale_ly) {
  228.           if (y_min < y_max) {
  229.              y_min = ytic * floor(y_min/ytic);       
  230.              y_max = ytic * ceil(y_max/ytic);
  231.           }
  232.           else {            /* reverse axis */
  233.              y_min = ytic * ceil(y_min/ytic);       
  234.              y_max = ytic * floor(y_max/ytic);
  235.           }
  236.        }
  237.     }
  238.  
  239.     if (xtics && xticdef.type == TIC_COMPUTED) {
  240.        xtic = make_tics(x_min,x_max,log_x);
  241.        
  242.        if (autoscale_lx) {
  243.           if (x_min < x_max) {
  244.              x_min = xtic * floor(x_min/xtic);    
  245.              x_max = xtic * ceil(x_max/xtic);
  246.           } else {
  247.              x_min = xtic * ceil(x_min/xtic);
  248.              x_max = xtic * floor(x_max/xtic);    
  249.           }
  250.        }
  251.     }
  252.  
  253. /*    This used be x_max == x_min, but that caused an infinite loop once. */
  254.     if (fabs(x_max - x_min) < zero)
  255.         int_error("x_min should not equal x_max!",NO_CARET);
  256.     if (fabs(y_max - y_min) < zero)
  257.         int_error("y_min should not equal y_max!",NO_CARET);
  258.  
  259. /* INITIALIZE TERMINAL */
  260.     if (!term_init) {
  261.         (*t->init)();
  262.         term_init = TRUE;
  263.     }
  264.     screen_ok = FALSE;
  265.      scaling = (*t->scale)(xsize, ysize);
  266.     (*t->graphics)();
  267.  
  268.      /* now compute boundary for plot (xleft, xright, ytop, ybot) */
  269.      boundary(scaling);
  270.  
  271. /* SCALE FACTORS */
  272.     yscale = (ytop - ybot)/(y_max - y_min);
  273.     xscale = (xright - xleft)/(x_max - x_min);
  274.     
  275. /* DRAW AXES */
  276.     (*t->linetype)(-1);    /* axis line type */
  277.     xaxis_y = map_y(0.0);
  278.     yaxis_x = map_x(0.0); 
  279.  
  280.     if (xaxis_y < ybot)
  281.         xaxis_y = ybot;                /* save for impulse plotting */
  282.     else if (xaxis_y >= ytop)
  283.         xaxis_y = ytop ;
  284.     else if (xzeroaxis && !log_y) {
  285.         (*t->move)(xleft,xaxis_y);
  286.         (*t->vector)(xright,xaxis_y);
  287.     }
  288.  
  289.     if (yzeroaxis && !log_x && yaxis_x >= xleft && yaxis_x < xright ) {
  290.         (*t->move)(yaxis_x,ybot);
  291.         (*t->vector)(yaxis_x,ytop);
  292.     }
  293.  
  294. /* DRAW TICS */
  295.     (*t->linetype)(-2); /* border linetype */
  296.  
  297.     /* label y axis tics */
  298.      if (ytics) {
  299.         switch (yticdef.type) {
  300.            case TIC_COMPUTED: {
  301.                if (y_min < y_max)
  302.                 draw_ytics(ytic * floor(